import sys
from PyQt6.QtWidgets import QApplication,QMainWindow,QPushButton,QVBoxLayout,QLabel
from PyQt6.QtCore import pyqtSignal,QUrl,pyqtSlot
from sls_mqttClient import MQTTClient
from ui_sls_gcv1 import Ui_MainWindow
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebChannel import QWebChannel
import io
import folium
import json
import math
from PyQt6.QtCore import QObject
from sls_gc_agent import sls_Agent

from sls_gc_missionslist import gc_MissionsList

import sls_coordinationConvert as sls_c




 # 镇江的江苏大学的经纬度119.515293, 32.199403
default_latitude = 32.199403
defualt_longitude = 119.515293

mglong,mglat = sls_c.gcj02_to_wgs84(defualt_longitude,default_latitude)

class NotifyClass():
    def __init__(self,parent):
        self.parent = parent
        self.notify_CordinateList = []

    def add_notify_Cordinate(self,func):
        self.notify_CordinateList.append(func)

    def notify_Cordinate(self,latitude,longitude):
        for item in self.notify_CordinateList:
            item(latitude,longitude)    

class MapInteraction(QObject):
    def __init__(self, main_window):
        super().__init__()  # 调用父类 QObject 的构造函数
        self.main_window = main_window

    @pyqtSlot(float, float)
    def showCoordinates(self, latitude, longitude):
        self.main_window.statusBar_signal.emit(f"点击位置坐标：{latitude}, {longitude}")
        self.main_window.notifyClass.notify_Cordinate(latitude,longitude)
    
    @pyqtSlot()
    def mapLoaded(self):
        self.main_window.statusBar_signal.emit(f"地图加载完成")
        self.main_window.mapLoadedFlag = True
    

class GCMainWindow(QMainWindow):
    statusBar_signal = pyqtSignal(str)
    mapUpdate_signal = pyqtSignal(str)
    show_uav_status_signal = pyqtSignal(str)
    show_uav_runingTask_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        self.fly1_missionslist = None
        self.fly2_missionslist = None

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.agent = sls_Agent()
        self.agent.set_agent_connect_callback(self.agent_connect_callback)
        self.agent.set_agent_update_callback(self.agent_update_callback)
        self.agent.set_runingTask_callback(self.agent_runingTask_callback)

        self.notifyClass = NotifyClass(self)
        
        self.show_uav_status_signal.connect(self.show_uav_status)
        self.show_uav_runingTask_signal.connect(self.show_uav_runingTask)


        self.statusBar_signal.connect(self.ui.statusbar.showMessage)
        self.ui.statusbar.showMessage("mqtt连接中...")

        # 创建 QWebEngineView 并添加到布局中
        self.web_view = QWebEngineView()
        self.ui.webhorizontalLayout.addWidget(self.web_view)
        self.mapUpdate_signal.connect(self.map_update)

        # 创建 QWebChannel 对象
        self.channel = QWebChannel()
        self.web_view.page().setWebChannel(self.channel)

        # 创建并注册只包含必要方法的对象
        self.map_interaction = MapInteraction(self)
        self.channel.registerObject('pyObj', self.map_interaction)

        # 初始化无人机箭头标记的 JavaScript 变量
        # self.arrow_marker_js_fly1 = None
        # self.fly1_js_code = None
        # self.arrow_marker_js_fly2 = None
        # self.fly2_js_code = None
        self.mapLoadedFlag = False

        self.generate_map()

        self.ui.uav1msButton.clicked.connect(self.fly1_open_Ms)
        self.ui.uav2msButton.clicked.connect(self.fly2_open_Ms)
        self.ui.uav1_startmsButton.clicked.connect(self.agent.fly1_start_Ms)
        self.ui.uav2_startmsButton.clicked.connect(self.agent.fly2_start_Ms)
        self.ui.uav1_stopmsButton.clicked.connect(self.agent.fly1_stop_Ms)
        self.ui.uav2_stopmsButton.clicked.connect(self.agent.fly2_stop_Ms)
        self.ui.uav1_restartmsButton.clicked.connect(self.agent.fly1_restart_Ms)
        self.ui.uav2_restartmsButton.clicked.connect(self.agent.fly2_restart_Ms)


        self.agent.mqtt_connect()


    def fly1_open_Ms(self):
        self.fly1_missionslist = gc_MissionsList(self,"fly1")
        #self.uav1msButton灰色不能用
        self.ui.uav1msButton.setEnabled(False)
        self.fly1_missionslist.show()

    def fly2_open_Ms(self):
        self.fly2_missionslist = gc_MissionsList(self,"fly2")
        #self.uav2msButton灰色不能用
        self.ui.uav2msButton.setEnabled(False)
        self.fly2_missionslist.show()

    def agent_connect_callback(self):
        self.statusBar_signal.emit("mqtt连接成功")
    
    def show_uav_runingTask(self, topic):
        def update_runingTask(msBox,uav_mirror):
            layout = msBox.layout()
            if layout:
                #遍历4个label，并按照顺序设置Text
                for i in range(layout.count()):
                    item = layout.itemAt(i)
                    widget = item.widget()
                    if isinstance(widget, QLabel):
                        if i == 0:
                            widget.setText(f"任务类型：{uav_mirror.runingTask['missionsType']}")
                            continue
                        elif i == 1:
                            widget.setText(f"数据：{uav_mirror.runingTask['datasets']}")
                            continue
        topic_mapping ={
            "/status/fly1/runingTask": lambda: (self.ui.fly1_MSBox, self.agent.uav_mirror_1),
            "/status/fly2/runingTask": lambda: (self.ui.fly2_MSBox, self.agent.uav_mirror_2),
        }
        for topic in topic_mapping:
                try:
                    msBox, uav_mirror = topic_mapping[topic]()
                    update_runingTask(msBox, uav_mirror)
                except Exception as e:
                    print(f"Error in show_uav_runingTask: {e}")
        # if topic == "/status/fly1/runingTask":
        #     #判断self.ui是否有fly1_MSBox的属性
        #     if hasattr(self.ui,"fly1_MSBox"):
        #         update_runingTask(self.ui.fly1_MSBox, self.agent.uav_mirror_1)
        # if topic == "/status/fly2/runingTask":
        #     if hasattr(self.ui,"fly2_MSBox"):
        #         update_runingTask(self.ui.fly2_MSBox, self.agent.uav_mirror_2)
        

    def agent_runingTask_callback(self, client, userdata, msg):
        self.statusBar_signal.emit("任务运行中")
        topic = msg.topic
        self.show_uav_runingTask_signal.emit(topic)

        
    

    def map_update(self, js_code):
        self.web_view.page().runJavaScript(js_code)


    def show_uav_status(self, topic):
        def update_uav_status(msBox,uav_mirror):
            stateLayout:QVBoxLayout = None
            layout = msBox.layout()
            if layout:
                for i in range(layout.count()):
                    item = layout.itemAt(i)
                    if isinstance(item, QVBoxLayout):
                        stateLayout = item
                        break
            if stateLayout:
                #遍历4个label，并按照顺序设置Text
                for i in range(stateLayout.count()):
                    item = stateLayout.itemAt(i)
                    widget = item.widget()
                    if isinstance(widget, QLabel):
                        if i == 0:
                            # 显示经度和纬度，保留两位小数
                            widget.setText(f"经度：{uav_mirror.GNSS_position['longitude']:.7f},纬度：{uav_mirror.GNSS_position['latitude']:.7f}")
                            continue
                        elif i == 1:
                            # 显示偏航角，保留两位小数
                            if uav_mirror.vehicle_yaw is None:
                                widget.setText(f"偏航角：None")
                                continue
                            widget.setText(f"偏航角/角度：{uav_mirror.vehicle_yaw * (180 / math.pi):.2f}")
                            continue
                        elif i == 2:
                            widget.setText(f"是否飞行：{uav_mirror.is_flying_status}")
                            continue
                        elif i == 3:
                            widget.setText(f"是否解锁：{uav_mirror.is_arming_status}")
                            continue
                        elif i == 4:
                            # 显示高度，保留两位小数
                            ned = uav_mirror.relative_altitude['NED']
                            msl = uav_mirror.relative_altitude['msl']
                            ell = uav_mirror.relative_altitude['ell']
                            laser = uav_mirror.relative_altitude['laser']
                            ned_str = f"{ned:.2f}" if ned is not None else str(ned)
                            msl_str = f"{msl:.2f}" if msl is not None else str(msl)
                            ell_str = f"{ell:.2f}" if ell is not None else str(ell)
                            laser_str = f"{laser:.2f}" if isinstance(laser, (int, float)) else str(laser)
                            widget.setText(f"NED：{ned_str}, msl：{msl_str}, ell：{ell_str}, laser：{laser_str}")
                            continue
        
        topic_mapping = {
            "/status/fly1/PR":("fly1_groupBox",lambda: self.ui.fly1_groupBox,lambda: self.agent.uav_mirror_1),
            "/status/fly2/PR":("fly2_groupBox",lambda: self.ui.fly2_groupBox,lambda: self.agent.uav_mirror_2)
        }
        if topic in topic_mapping:
            msBoxName,get_msBox,get_uav_mirror = topic_mapping[topic]
            try:
                msBox = get_msBox()
                uav_mirror = get_uav_mirror()
                update_uav_status(msBox,uav_mirror)
            except Exception as e:
                print(f"Error updating {msBoxName}: {e}")
        # if topic == "/status/fly1/PR":
        #     if hasattr(self.ui,"fly1_groupBox"):
        #         update_uav_status(self.ui.fly1_groupBox, self.agent.uav_mirror_1)
        # if topic == "/status/fly2/PR":
        #     if hasattr(self.ui,"fly2_groupBox"):
        #         update_uav_status(self.ui.fly2_groupBox, self.agent.uav_mirror_2)

    def agent_update_callback(self, client, userdata, msg):
        #该函数要短
        self.show_uav_status_signal.emit(msg.topic)

        if self.mapLoadedFlag == False:
            return
        topic = msg.topic
        topic_mapping = {
            "/status/fly1/PR": ("updateFly1ArrowMarker", lambda: self.agent.uav_mirror_1),
            "/status/fly2/PR": ("updateFly2ArrowMarker", lambda: self.agent.uav_mirror_2)
        }
        js_code = ''
        if topic in topic_mapping:
            function_name, get_uav_mirror = topic_mapping[topic]
            uav_mirror = get_uav_mirror()
            longitudegc,latitudegc = sls_c.wgs84_to_gcj02(uav_mirror.GNSS_position["longitude"], uav_mirror.GNSS_position["latitude"])
            if uav_mirror.vehicle_yaw is None:
                return
            js_code += f'{function_name}({latitudegc}, {longitudegc}, {uav_mirror.vehicle_yaw * (180 / math.pi)});'

        self.mapUpdate_signal.emit(js_code)
    
    def add_marker(self, latitude, longitude, name):
        js_code = f'createMarker({latitude},{longitude},"{name}");'
        self.mapUpdate_signal.emit(js_code)

    def delete_marker(self, name):
        js_code = f'deleteMarker("{name}");'
        self.mapUpdate_signal.emit(js_code)

    def generate_map(self):
        # 创建 folium 地图对象（修正初始缩放级别为18）
        m = folium.Map(location=[default_latitude, defualt_longitude],zoom_start=18, control_scale=True, max_zoom=22)

        # 修改高德普通地图瓦片配置（添加 tile_url_function）
        gaode_normal_tiles = folium.TileLayer(
            tiles='http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
            attr='高德地图',
            subdomains='1234',
            max_zoom=18,
            name='高德普通地图'
        )

        # 修改高德卫星地形图瓦片配置（添加 tile_url_function）
        gaode_satellite_tiles = folium.TileLayer(
            tiles='http://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
            attr='高德地图',
            subdomains='1234',
            max_zoom=18,
            name='高德卫星地形图'
        )
        gaode_normal_tiles.add_to(m)

        # 添加高德卫星地形图瓦片
        gaode_satellite_tiles.add_to(m)

        # 添加标记到地图上，并添加自定义属性
        # marker = folium.Marker([default_latitude, defualt_longitude], icon=folium.Icon(color='blue'))
        # marker2 = folium.Marker([mglat, mglong], icon=folium.Icon(color='red'))
        # # 给标记添加自定义属性
        # marker.add_to(m)
        # marker2.add_to(m)
        # marker._id = 'location_marker'

        # 添加图层控制
        folium.LayerControl().add_to(m)

        # 保存地图为 HTML 文件
        data = io.BytesIO()
        m.save(data, close_file=False)
        html_content = data.getvalue().decode()

        # 注入 QWebChannel.js 和必要的样式
        html_content = html_content.replace('</body>', """
        <script src="qrc:///qtwebchannel/qwebchannel.js"></script> <!-- 注入 qwebchannel.js -->
        <style>
        .leaflet-container {
            cursor: crosshair !important;
        }
        /* 隐藏 Leaflet 版权信息 */
        .leaflet-control-attribution {
            display: none;
        }
        </style>

        <script>
        // 全局变量，用于保存 Leaflet 地图对象
        var globalMap;
        var fly1_arrowMarker;
        var fly2_arrowMarker;
        var markerDict = {}; // 用于存储所有 marker，键为名字，值为 marker 对象

        // 监听 DOM 加载完成事件
        document.addEventListener('DOMContentLoaded', function() {
            // 每隔 100 毫秒检查 Leaflet 地图是否加载完成
            var checkLeaflet = setInterval(function() {
                // 过滤出所有 Leaflet 地图对象
                var maps = Object.values(window).filter(function(value) {
                    return value && value._initHooksCalled && value.getContainer;
                });

                // 如果找到地图对象，则清除定时器
                if (maps.length > 0) {
                    clearInterval(checkLeaflet);
                    globalMap = maps[0];

                    // 等待 QWebChannel 初始化完成
                    new QWebChannel(qt.webChannelTransport, function(channel) {
                        var pyObj = channel.objects.pyObj;

// 定义旋转标记类 不要改变这里面的内容
(function() {
    // save these original methods before they are overwritten
    var proto_initIcon = L.Marker.prototype._initIcon;
    var proto_setPos = L.Marker.prototype._setPos;

    var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');

    L.Marker.addInitHook(function () {
        var iconOptions = this.options.icon && this.options.icon.options;
        var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;
        if (iconAnchor) {
            iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');
        }
        this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom' ;
        this.options.rotationAngle = this.options.rotationAngle || 0;

        // Ensure marker keeps rotated during dragging
        this.on('drag', function(e) { e.target._applyRotation(); });
    });

    L.Marker.include({
        _initIcon: function() {
            proto_initIcon.call(this);
        },

        _setPos: function (pos) {
            proto_setPos.call(this, pos);
            this._applyRotation();
        },

        _applyRotation: function () {
            if(this.options.rotationAngle) {
                this._icon.style[L.DomUtil.TRANSFORM+'Origin'] = this.options.rotationOrigin;

                if(oldIE) {
                    // for IE 9, use the 2D rotation
                    this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
                } else {
                    // for modern browsers, prefer the 3D accelerated version
                    this._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';
                }
            }
        },

        setRotationAngle: function(angle) {
            this.options.rotationAngle = angle;
            this.update();
            return this;
        },

        setRotationOrigin: function(origin) {
            this.options.rotationOrigin = origin;
            this.update();
            return this;
        }
    });
})();
                        pyObj.mapLoaded();
                        // 添加地图点击事件监听
                        globalMap.on('click', function(e) {
                            var lat = e.latlng.lat;
                            var lng = e.latlng.lng;
                            pyObj.showCoordinates(lat, lng);
                        });
                    });
                }
            }, 100);
        });

        // 根据坐标位置和名字创建 marker
        function createMarker(latitude, longitude, name) {
            var customIcon = L.divIcon({
                html: '<div style="width: 20px; height: 20px; background-color: green; border-radius: 50%;"></div>',
                iconSize: [20, 20],
                iconAnchor: [10, 10]
            });
            var marker = L.marker([latitude, longitude], {icon: customIcon}).addTo(globalMap);
            markerDict[name] = marker;
            return marker;
        }

        // 删除指定名字的 marker
        function deleteMarker(name) {
            if (markerDict[name]) {
                markerDict[name].remove();
                delete markerDict[name];
            }
        }

        function updateFly1ArrowMarker(latitude, longitude, angle) {
            if (!fly1_arrowMarker) {
                fly1_arrowIcon = L.divIcon({
                    html: '<div style="width: 0; height: 0; border-left: 15px solid transparent; border-right: 15px solid transparent; border-bottom: 40px solid red;"></div>',
                    iconSize: [0, 0],
                    iconAnchor: [15, 20]

                });
                fly1_arrowMarker = L.marker([latitude, longitude], {icon: fly1_arrowIcon, rotationAngle: angle}).addTo(globalMap);
            } else {
                fly1_arrowMarker.setLatLng([latitude, longitude]).setRotationAngle(angle);
            }
        }
        function updateFly2ArrowMarker(latitude, longitude, angle) {
            if (!fly2_arrowMarker) {
                fly2_arrowIcon = L.divIcon({
                    html: '<div style="width: 0; height: 0; border-left: 15px solid transparent; border-right: 15px solid transparent; border-bottom: 40px solid blue;"></div>',
                    iconSize: [0, 0],
                    iconAnchor: [15, 20]
                });
                fly2_arrowMarker = L.marker([latitude, longitude], {icon: fly2_arrowIcon, rotationAngle: angle}).addTo(globalMap);
            } else {
                fly2_arrowMarker.setLatLng([latitude, longitude]).setRotationAngle(angle);
            }
        }          
        </script>
        </body>
        """)

        # 设置 baseUrl 以确保可以加载 qwebchannel.js
        self.web_view.setHtml(html_content, baseUrl=QUrl("qrc:/"))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = GCMainWindow()
    main_window.show()
    sys.exit(app.exec())
